﻿namespace SharpF2.Services
{
	using System;
	using System.Collections.ObjectModel;
	using System.ComponentModel;
	using System.Diagnostics;
	using System.Globalization;
	using System.IO;

	/// <summary>
	/// Define a log manager witch a singleton and a INotifyPropertyChanged
	/// </summary>
	public class LoggingService : INotifyPropertyChanged
	{
		#region Events

		/// <summary>
		/// Event raised when a property has changed.
		/// </summary>
		public event PropertyChangedEventHandler PropertyChanged;

		#endregion

		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="LoggingService" /> class. 
		/// Constructor.
		/// </summary>
		static LoggingService()
		{
			Log = new ObservableCollection<String>();
			logFilePath = GenerateDefaultLogFileName();
		}

		#endregion

		#region Private Attributes

		private static readonly LoggingService instance = new LoggingService();

		/// <summary>
		/// The current log file path.
		/// </summary>
		private static String logFilePath;

		#endregion

		#region Public Properties

		public static LoggingService Instance
		{
			get { return instance; }
		}

		/// <summary>
		/// Gets a collection of string, each item correspond to an event.
		/// </summary>
		public static ObservableCollection<String> Log { get; private set; }

		#endregion

		#region Public Members

		/// <summary>
		/// Generate the default log file name.
		/// </summary>
		/// <returns>
		/// The default log file name.
		/// </returns>
		public static String GenerateDefaultLogFileName()
		{
			var directoryPath = AppDomain.CurrentDomain.BaseDirectory + @"/Logs/";
			if (Directory.Exists(directoryPath) == false)
				Directory.CreateDirectory(directoryPath);

			var dateTime = DateTime.Now;
			return directoryPath +
			       dateTime.Year +
			       dateTime.Month.ToString("D2", CultureInfo.InvariantCulture) +
			       dateTime.Day.ToString("D2", CultureInfo.InvariantCulture) +
			       dateTime.Hour.ToString("D2", CultureInfo.InvariantCulture) +
			       dateTime.Minute.ToString("D2", CultureInfo.InvariantCulture) +
			       " - " +
			       dateTime.Ticks +
			       ".log";
		}

		/// <summary>
		/// Writes a message to the application event log
		/// </summary>
		/// <param name="source">Source is the source of the message ususally you will want this to be the application name.</param>
		/// <param name="message">Message to be written.</param>
		/// <param name="entryType">The entry type to use to categorize the message like for exmaple error or information.</param>
		public static void WriteToEventLog(String source, String message, EventLogEntryType entryType)
		{
			try
			{
				if (!EventLog.SourceExists(source))
					EventLog.CreateEventSource(source, "Application");

				EventLog.WriteEntry(source, message, entryType);
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.Message);
			}
		}

		/// <summary>
		/// Generate a default log file name to use;
		/// </summary>
		public void NewFile()
		{
			logFilePath = GenerateDefaultLogFileName();
		}

		/// <summary>
		/// Pass in the fully qualified name of the log file you want to write to
		/// and the message to write.
		/// </summary>
		/// <param name="message">The message to log</param>
		public void WriteToLog(String message)
		{
			var localLogFilePath = logFilePath;
			if (!String.IsNullOrEmpty(logFilePath))
				localLogFilePath = logFilePath;

			var wSW = !File.Exists(localLogFilePath) ? File.CreateText(localLogFilePath) : File.AppendText(localLogFilePath);
			try
			{
				var localMessage = DateTime.Now + "\t" + message;
				Log.Add(localMessage);
				wSW.WriteLine(localMessage);
				wSW.Flush();
				wSW.Close();
				InvokePropertyChanged("Log");
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex.Message);
			}
		}

		#endregion

		#region Private Members

		/// <summary>
		/// Raise the event PropertyChanged.
		/// </summary>
		/// <param name="e">The PropertyName.</param>
		private void InvokePropertyChanged(String e)
		{
			var handler = PropertyChanged;
			if (handler != null)
				handler(this, new PropertyChangedEventArgs(e));
		}

		#endregion
	}
}